﻿Imports RapidConsole

''' <summary>
''' Provides a window which displays a selectable list of strings.
''' </summary>
Public Class ListWindow
    Inherits Window
    Public Event ItemSelected As EventHandler
    Public Event SelectedIndexChanged As EventHandler

    Private indexChange As Action

    Public ReadOnly Property Item(index As Integer) As String
        Get
            If index > -1 AndAlso index < Content.LineCount Then
                Return Content.GetLineText(Content.Lines(index)).TrimEnd() 'Text.Split({vbCr, vbLf}, StringSplitOptions.RemoveEmptyEntries)(index)
            End If
            Return String.Empty
        End Get
    End Property

    Private _SelectedIndex As Integer = -1
    Public Property SelectedIndex As Integer
        Get
            Return _SelectedIndex
        End Get
        Set(value As Integer)
            _SelectedIndex = value
        End Set
    End Property

    Public Sub New(x As Integer, y As Integer, width As Integer, height As Integer)
        MyBase.New(x, y, width, height)
    End Sub

    Public Sub Add(item As String, Optional autoSize As Boolean = True)
        AppendText(item, True)
        If autoSize Then AutoSizeWindow()
    End Sub

    Public Sub AutoSizeWindow()
        Dim lines As New List(Of String)(Content.Text.Split({ControlChars.Lf}, StringSplitOptions.None))
        Dim maxWidth As Integer
        For Each line In lines
            line = line.Trim
            If line.Length > maxWidth Then maxWidth = line.Length
        Next
        maxWidth += 1
        If maxWidth >= ClientBounds.Width Then
            If FrameVisible Then maxWidth += 2
            Bounds = New Rectangle(Bounds.Left, Bounds.Top, maxWidth, Bounds.Height)
        End If
        Content.UpdateContents()
    End Sub

    Public Sub RemoveAt(index As Integer)
        If index > -1 Then
            'Dim lines As New List(Of String)(Text.Split({vbCr, vbLf}, StringSplitOptions.RemoveEmptyEntries))
            If index < Content.LineCount Then
                Dim lines As List(Of String) = Content.Lines
                lines.RemoveAt(index)
                Content.Text = String.Join(ControlChars.NewLine, lines.ToArray)
            End If
            _SelectedIndex = index - 1
        End If
    End Sub

    Protected Overrides Function GetBackcolor(x As Integer, y As Integer) As ConsoleColor
        Dim dy = SelectedIndex + ClientBounds.Top - firstLineVisible
        Dim p = Parent
        While p IsNot Nothing
            dy += p.ClientBounds.Top - 1
            p = p.Parent
        End While
        If y = dy Then
            Return ForeColor
        Else
            Return BackColor
        End If
    End Function

    Protected Overrides Function GetForecolor(x As Integer, y As Integer) As ConsoleColor
        Dim dy = SelectedIndex + ClientBounds.Top - firstLineVisible
        Dim p = Parent
        While p IsNot Nothing
            dy += p.ClientBounds.Top - 1
            p = p.Parent
        End While
        If y = dy Then
            Return BackColor
        Else
            Return ForeColor
        End If
    End Function

    Protected Overridable Sub OnItemSelected(e As EventArgs)
        RaiseEvent ItemSelected(Me, e)
    End Sub

    Protected Overridable Sub OnSelectedIndexChanged(e As EventArgs)
        RaiseEvent SelectedIndexChanged(Me, e)
    End Sub

    Protected Overrides Sub OnShown(e As EventArgs)
        MyBase.OnShown(e)
        _SelectedIndex = 0
        firstLineVisible = 0
    End Sub

    Protected Overrides Sub OnPostDraw()
        MyBase.OnPostDraw()
        If indexChange IsNot Nothing Then
            Dim oldIndex = _SelectedIndex
            indexChange()
            indexChange = Nothing
            Window.ClearBackground(Me)
            Window.DrawText(Me)
            Window.ClearChildBackgrounds(Me.Children)
            If Not _SelectedIndex = oldIndex Then
                OnSelectedIndexChanged(EventArgs.Empty)
                oldIndex = _SelectedIndex
            End If
        End If
    End Sub

    Private Sub ListWindow_KeyProcessing(sender As Object, e As KeyProcessingEventArgs) Handles Me.KeyProcessing
        Dim dix As Integer = 0
        Dim canSuppress As Boolean = False
        Select Case e.Key.Key
            Case ConsoleKey.Enter
                OnItemSelected(EventArgs.Empty)
            Case ConsoleKey.UpArrow
                indexChange = New Action(Sub() If _SelectedIndex > 0 Then _SelectedIndex -= 1)
                If _SelectedIndex > 0 Then dix = -1
                canSuppress = True
            Case ConsoleKey.DownArrow
                indexChange = New Action(Sub() If _SelectedIndex < Content.LineCount - 1 Then _SelectedIndex += 1)
                If _SelectedIndex < Content.LineCount - 1 Then dix = 1
                canSuppress = True
        End Select
        If canSuppress Then
            If _SelectedIndex + dix >= firstLineVisible AndAlso _SelectedIndex + dix <= firstLineVisible + ClientBounds.Height - 1 Then
                e.SuppressDefaultProcessing = True
            Else
                e.SuppressDefaultProcessing = False
            End If
        End If
    End Sub
End Class
